<?php
/**
 * CustomerRepo.php
 *
 * @copyright   2023 thingsworld.com.cn - All Rights Reserved
 * @link        http://thingsworld.com.cn/
 * @author      stiffer.chen <chenl@thingsworld.com.cn>
 * @created     2023-02-14 04:33:59
 * @modified    2023-02-14 04:33:59
 *
 */

namespace App\Repositories;

use App\Models\CityModel;
use App\Models\Customer;
use App\Models\DeptModel;
use App\Models\DictModel;
use App\Models\Event;
use App\Models\Product;
use App\Models\User;
use App\Models\UserModel;
use App\Repositories\Customer\UserRepo;
use Carbon\Carbon;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

class CustomerRepo
{
    const CUSTOMER_TYPE_CUSTOMER = '客户';
    const CUSTOMER_TYPE_PROVIDER = '供应商';
    const CUSTOMER_TYPE_DIS = '分销商';
    const CUSTOMER_TYPE_PAR = '合作伙伴';
    const CUSTOMER_TYPE_PUB = '公共媒体';
    const CUSTOMER_TYPE_BANK = '银行';
    const CUSTOMER_TYPE_AGE = '中介';
    const CUSTOMER_TYPE_OUT = '外部资源';
    const CUSTOMER_TYPE_COMPETE = '竞争对手';
    const CUSTOMER_TYPE_PERSONAL = '个人用户';

    const CUSTOMER_INDUSTRY_ENERGY = '新能源';
    const CUSTOMER_INDUSTRY_AUTO = '汽车';
    const CUSTOMER_INDUSTRY_MANU = '智能制造';
    const CUSTOMER_INDUSTRY_CHE = '化工';
    const CUSTOMER_INDUSTRY_MEDICAL = '医疗';

    const CUSTOMER_PROPERTY_COM = '国企';
    const CUSTOMER_PROPERTY_POP = '民企';
    const CUSTOMER_PROPERTY_OUT = '外资';
    const CUSTOMER_PROPERTY_MERGE = '合资';

    const CUSTOMER_TAG_IMP = '重要';
    const CUSTOMER_TAG_NOR = '一般';
    const CUSTOMER_TAG_CORE = '核心';
    const CUSTOMER_TAG_VIP = 'VIP';

    const CUSTOMER_SAFE_A = 'A类';
    const CUSTOMER_SAFE_B = 'B类';
    const CUSTOMER_SAFE_C = 'C类';

    const CUSTOMER_SOURCE_OPEN = '企业开拓';
    const CUSTOMER_SOURCE_CON = '主动联系';
    const CUSTOMER_SOURCE_REC = '客户推荐';
    const CUSTOMER_SOURCE_CONN = '企业人脉';

    const CUSTOMER_NUMBER_PREFIX = 'CUS';

    public static function params()
    {
        $dictTypes = ['客户类型', '客户来源', '客户行业', '客户性质', '客户标签', '客户安全等级'];
        $builder = DictModel::query()
            ->from('dict as d')
            ->join('dict_data as dd', 'dd.dict_id', '=', 'd.id')
            ->whereIn('d.name', $dictTypes)
            ->where('dd.mark', 1)
            ->select(['d.name as type_name', 'dd.name as item_name']);
        $dicts = $builder->get()->groupBy('type_name')->toArray();

        $types = $industries = $properties = $tags = $levels = $sources = [];

        $types = collect($dicts['客户类型'] ?? [])->pluck('item_name')->toArray();
        $industries = collect($dicts['客户行业'] ?? [])->pluck('item_name')->toArray();
        $properties = collect($dicts['客户性质'] ?? [])->pluck('item_name')->toArray();
        $tags = collect($dicts['客户标签'] ?? [])->pluck('item_name')->toArray();
        $levels = collect($dicts['客户安全等级'] ?? [])->pluck('item_name')->toArray();
        $sources = collect($dicts['客户来源'] ?? [])->pluck('item_name')->toArray();
        return [
            'types' => $types,
            'industries' => $industries,
            'properties' => $properties,
            'tags' => $tags,
            'levels' => $levels,
            'sources' => $sources
        ];
    }

    public static function storeUser($customerId)
    {
        $customer = Customer::find($customerId);
        if (empty($customer)) {
            throw new \Exception('客户信息不存在');
        }
        $customerUserData = request()->getContent();
        $customerUserArr = json_decode($customerUserData, true);

        $customerUserId = intval($customerUserArr['customer_user_id'] ?? 0);
        $customerUser = Customer\User::find($customerUserId);
        if (empty($customerUser)) {
            $customerUser = new Customer\User();
            $contactName = trim($customerUserArr['contact_name'] ?? '');
        } else {
            $contactName = $customerUser->name;
        }

        if (!$contactName) {
            throw new \Exception('联系人姓名不能为空');
        }

        $contactPhone = trim($customerUserArr['contact_phone'] ?? '');

        if (!$contactPhone) {
            throw new \Exception('联系电话不能为空');
        }

        $provinceId = intval($customerUserArr['province_id'] ?? 0);
        if (!$provinceId) {
            throw new \Exception('请选择省份');
        }

        $province = CityModel::find($provinceId);
        if (empty($province)) {
            throw new \Exception('省份信息不存在');
        }

        $cityId = intval($customerUserArr['city_id'] ?? 0);
        if (!$cityId) {
            throw new \Exception('请选择城市');
        }
        $city = CityModel::find($cityId);
        if (empty($city)) {
            throw new \Exception('城市信息不存在');
        }
        if ($city->pid != $provinceId) {
            throw new \Exception('所选城市非当前省份所属');
        }

        $countyId = intval($customerUserArr['county_id'] ?? 0);
        if (!$countyId) {
            throw new \Exception('请选择区县');
        }
        $county = CityModel::find($countyId);
        if (empty($county)) {
            throw new \Exception('区县信息不存在');
        }
        if ($county->pid != $cityId) {
            throw new \Exception('所选区县非当前城市所属');
        }
        $address = trim($customerUserArr['address'] ?? 0);
        if (!$address) {
            throw new \Exception('请输入详细地址');
        }

        $customerUserData = [
            'name' => $contactName,
            'phone' => $contactPhone,
            'office_phone' => '',
            'email' => '',
            'birthday' => '',
            'duty' => '',
            'project_role' => '',
            'customer_id' => $customer->id,
            'customer_name' => $customer->name,
            'country_id' => 0,
            'country_name' => '',
            'province_id' => $provinceId,
            'province_name' => $province->name ?? '',
            'city_id' => $cityId ?? 0,
            'city_name' => $city->name ?? '',
            'county_id' => $countyId ?? 0,
            'county_name' => $county->name ?? '',
            'address' => $address,
            'status' => 1,
            'create_user_id' => $customer->create_user_id ?? 0
        ];

        $customerUser->fill($customerUserData);
        $customerUser->saveOrFail();

        $eventId = $customerUserArr['event_id'] ?? 0;
        if ($eventId) {
            $event = Event::find($eventId);
            if (!empty($event)) {
                $event->customer_id = $customer->id;
                $event->customer_name = $customer->name;
                $event->customer_user_id = $customerUser->id;
                $event->contact_name = $contactName;
                $event->contact_telephone = $contactPhone;
                $event->saveOrFail();
            }
        }

        return UserRepo::one($customerUser->id);
    }

    public static function export()
    {
        $pathPrefix = 'downloads/customers/' . date('Y/m/d/');
        $prefix = public_path() . '/' . $pathPrefix;
        $excelFileName = 'customer-' . md5(date('YmdHis') . microtime()) . '.xlsx';
        if (!is_dir($prefix)) {
            mkdir($prefix, 0777, true);
        }
        $excelFilePath = $prefix . $excelFileName;
        $spreadsheet = new Spreadsheet();
        $sheet = new Worksheet($spreadsheet, "客户数据");
        $spreadsheet->addSheet($sheet);
        $spreadsheet->removeSheetByIndex(0);

        $excelData = [];
        $excelData[] = [
            '*客户编号',
            '*客户名称',
            '*客户简称',
            '*联系人',
            '电话',
            '*地址',
            '邮箱',
            '客户行业',
            '签约日期',
            '服务部门/网点',
            '客户负责人',
            '备注信息'
        ];

        $customerData = self::getCustomerForExport();
        $customerData = array_merge($excelData, $customerData);

        $sheet->fromArray($customerData);
        $writer = new Xlsx($spreadsheet);
        $writer->save($excelFilePath);
        return env('APP_URL') . '/' . $pathPrefix . $excelFileName;
    }

    private static function getCustomerForExport()
    {
        $builder = Customer::query()
            ->select([
                'customer.customer_number',
                'customer.name',
                'customer.short_name',
                'customer_user.name as customer_name',
                'customer_user.phone',
                'customer_user.province_name',
                'customer_user.city_name',
                'customer_user.county_name',
                'customer_user.address',
                'customer_user.email',
                'customer.industry_name',
                'customer.contact_at',
                'customer.department_name',
                'customer.owner_name'
            ])
            ->join('customer_user', 'customer_user.customer_id', '=', 'customer.id');
        $customers = $builder->get();
        $result = [];
        foreach ($customers->toArray() as $item) {
            $result[] = [
                ' ' . $item['customer_number'],
                ' ' . $item['name'],
                ' ' . $item['short_name'],
                ' ' . $item['customer_name'],
                ' ' . $item['phone'],
                ' ' . $item['province_name'] . $item['city_name'] . $item['county_name'] . $item['address'],
                ' ' . $item['email'],
                ' ' . $item['industry_name'],
                ' ' . $item['contact_at'],
                ' ' . $item['department_name'],
                ' ' . $item['owner_name'],
                ""
            ];
        }
        return $result;
    }

    public static function generateCustomerNumber($id): string
    {
        $customer = Customer::find($id);
        if (!empty($customer)) {
            return $customer->customer_number;
        }
        $customerNumber = self::CUSTOMER_NUMBER_PREFIX . rand(1000000, 9999999);
        $customerCount = Customer::byCustomerNumber($customerNumber)->count();
        if ($customerCount) {
            return self::generateCustomerNumber($id);
        }
        return $customerNumber;
    }

    public static function store($id)
    {
        $customerData = self::requestData($id);
        if ($id) {
            $customer = Customer::find($id);
        } else {
            $customer = new Customer();
        }
        if (empty($customer)) {
            $customer = new Customer();
        }

        $customer->fill($customerData);
        $customer->saveOrFail();

        $contactName = trim($customerData['contact_name']);
        $contactPhone = trim($customerData['contact_phone']);
        $customerUserId = 0;

        if ($contactName && $contactPhone) {
            $customerUser = Customer\User::query()->where('customer_id', $customer->id)
                ->where('phone', $contactPhone)
                ->first();
            if (empty($customerUser)) {
                $customerUser = new Customer\User();
            }
            $customerUserData = [
                'name' => $contactName,
                'phone' => $contactPhone,
                'office_phone' => '',
                'email' => '',
                'birthday' => '',
                'duty' => '',
                'project_role' => '',
                'customer_id' => $customer->id,
                'customer_name' => $customer->name,
                'country_id' => 0,
                'country_name' => '',
                'province_id' => $customer->province_id ?? 0,
                'province_name' => $customer->province_name ?? '',
                'city_id' => $customer->city_id ?? 0,
                'city_name' => $customer->city_name ?? '',
                'county_id' => $customer->county_id ?? 0,
                'county_name' => $customer->county_name ?? '',
                'address' => $customer->address ?? '',
                'status' => 1,
                'create_user_id' => $customer->create_user_id ?? 0
            ];

            $customerUser->fill($customerUserData);
            $customerUser->saveOrFail();
            $customerUserId = $customerUser->id;
        }

        $eventId = $customerData['event_id'] ?? 0;
        if ($eventId) {
            $event = Event::find($eventId);
            if (!empty($event)) {
                $event->customer_id = $customer->id;
                $event->customer_name = $customer->name;
                if ($customerUserId) {
                    $event->customer_user_id = $customerUserId;
                }
                if ($contactName) {
                    $event->contact_name = $contactName;
                }
                if ($contactPhone) {
                    $event->contact_telephone = $contactPhone;
                }
                $event->saveOrFail();
            }
        }

        return self::fetch($customer->id);
    }

    public static function fetch($id)
    {
        $customer = Customer::with(['users', 'department.manager', 'owner', 'parent'])->find($id);
        if (empty($customer)) {
            throw new \Exception('客户不存在');
        }
        return $customer;
    }

    public static function destroy($id)
    {
        $customer = Customer::with('user')->find($id);
        if (empty($customer)) {
            return;
        }
        $customer->delete();
    }

    public static function destroy_batch()
    {
        $ids = request()->get('ids');
        $idsArr = explode(',', $ids);
        foreach ($idsArr as $id) {
            self::destroy($id);
        }
    }

    public static function getList()
    {
        $perPage = (int)request('limit');
        if ($perPage < 1) {
            $perPage = 1;
        }

        $builder = Customer::query()->with(['users', 'department.manager', 'owner', 'parent', 'user', 'create_user']);

        $keyword = trim(request()->get('keyword') ?? '');
        $status = trim(request()->get('status'));
        $departmentId = intval(request()->get('department_id') ?? 0);
        $ownerId = intval(request()->get('owner_id') ?? 0);
        if ($status != '') {
            $status = (int)$status;
            if ($status) {
                $queryStatus = 1;
            } else {
                $queryStatus = 0;
            }
        }

        if ($keyword) {
            $builder->where(function ($query) use ($keyword) {
                return $query->where('name', 'like', "%{$keyword}%")
                    ->orWhere('short_name', 'like', "%{$keyword}%")
                    ->orWhere('entry_type_name', 'like', "%{$keyword}%")
                    ->orWhere('industry_name', 'like', "%{$keyword}%")
                    ->orWhere('safe_level', 'like', "%{$keyword}%")
                    ->orWhere('source', 'like', "%{$keyword}%");
            });
        }
        if ($departmentId) {
            $builder->where('department_id', $departmentId);
        }
        if ($ownerId) {
            $builder->where('owner_id', $ownerId);
        }
        if ($status !== '') {
            $builder->where('status', $queryStatus);
        }

        $builder->orderByDesc('id');

        return $builder->paginate($perPage);
    }

    public static function users($id)
    {
        $customer = Customer::find($id);
        if (empty($customer)) {
            return [];
        }
        $users = $customer->users;
        return $users;
    }

    public static function products($id)
    {
        $customer = Customer::find($id);
        if (empty($customer)) {
            return [];
        }
        $productName = request()->get('product_name') ?? '';
        $builder = Product::with(['type'])->where('customer_id', $id);
        if ($productName) {
            $builder->where('name', 'like', "%{$productName}%");
        }
        $products = $builder->get();
        return $products;
    }

    public static function setDefaultUser($customerId, $customerUserId)
    {
        $customer = Customer::find($customerId);
        if (empty($customer)) {
            throw new \Exception('客户不存在');
        }
        $customerUser = Customer\User::find($customerUserId);
        if (empty($customerUser)) {
            throw new \Exception('联系人不存在');
        }
        $customer->customer_user_id = $customerUserId;
        $customer->saveOrFail();
    }

    private static function requestData($id)
    {
        $customerData = request()->getContent();
        $customerArr = json_decode($customerData, true);

        $eventId = $customerArr['event_id'] ?? 0;

        $parentId = $customerArr['parent_id'] ?? 0;
        if ($id && $parentId && $parentId == $id) {
            throw new \Exception('不能将自身作为父级');
        }
        // 客户编号
        $customerNumber = self::generateCustomerNumber($id);
        // 客户名称
        $name = trim($customerArr['name'] ?? '');
        if (!$name) {
            throw new \Exception('请输入客户名称');
        }

        $nameCustomer = Customer::byName($name)->first();
        if (!$id && !empty($nameCustomer)) {
            throw new \Exception('客户名称已被使用');
        }
        if ($id && $nameCustomer && $nameCustomer->id != $id) {
            throw new \Exception('客户名称已被使用');
        }
        $shortName = trim($customerArr['short_name'] ?? '');
        $entryTypeName = trim($customerArr['entry_type_name'] ?? '');
        $countryId = 0;

        $provinceId = $customerArr['province_id'] ?? 0;
        $province = CityModel::byCityCode($provinceId)->first();
        if (empty($province)) {
            $province = CityModel::find($provinceId);
        }
        $provinceName = $province->name ?? '';

        $cityId = $customerArr['city_id'] ?? 0;
        $city = CityModel::byCityCode($cityId)->first();
        if (empty($city)) {
            $city = CityModel::find($cityId);
        }
        $cityName = $city->name ?? '';

        $countyId = $customerArr['county_id'] ?? 0;
        $county = CityModel::byCityCode($countyId)->first();
        if (empty($county)) {
            $county = CityModel::find($countyId);
        }
        $countyName = $county->name ?? '';

        $address = trim($customerArr['address'] ?? '');

        $industryName = trim($customerArr['industry_name'] ?? '');
        $customerTypeName = trim($customerArr['customer_type_name'] ?? '');
        $departmentId = $customerArr['department_id'] ?? 0;
        $department = DeptModel::find($departmentId);
        $departmentName = $department->name ?? '';

        $tagName = trim($customerArr['tag_name'] ?? '');
        $safeLevel = trim($customerArr['safe_level'] ?? '');

        $source = trim($customerArr['source'] ?? '');

        // 负责人
        $ownerId = $customerArr['owner_id'] ?? 0;
        $owner = UserModel::find($ownerId);
        $ownerName = $owner->realname ?? '';
        $status = $customerArr['status'] ?? '';
        if ($status != '') {
            $status = (int)$status;
            if ($status) {
                $status = 1;
            } else {
                $status = 0;
            }
        } else {
            $status = 1;
        }

        $contactAt = trim($customerArr['contact_at'] ?? '');
        if (!$contactAt) {
            throw new \Exception('请选择签约日期');
        }
        $contactAt = Carbon::parse($contactAt)->toDateString();

        $contactName = trim($customerArr['contact_name'] ?? '');
        $contactPhone = trim($customerArr['contact_phone'] ?? '');
        if (($contactName && !$contactPhone) || ($contactPhone && !$contactName)) {
            throw new \Exception('请完善联系人信息');
        }

        $result = [
            'customer_number' => $customerNumber,
            'name' => $name,
            'short_name' => $shortName,
            'entry_type_name' => $entryTypeName,
            'country_id' => $countryId,
            'country_name' => '',
            'province_id' => $provinceId,
            'province_name' => $provinceName,
            'city_id' => $cityId,
            'city_name' => $cityName,
            'county_id' => $countyId,
            'county_name' => $countyName,
            'address' => $address,
            'industry_name' => $industryName,
            'customer_type_name' => $customerTypeName,
            'department_id' => $departmentId,
            'department_name' => $departmentName,
            'tag_name' => $tagName,
            'safe_level' => $safeLevel,
            'source' => $source,
            'owner_id' => $ownerId,
            'owner_name' => $ownerName,
            'status' => $status,
            'contact_at' => $contactAt,
            'service_limit' => 10,
            'event_id' => $eventId,
            'contact_name' => $contactName,
            'contact_phone' => $contactPhone
        ];

        if ($parentId) {
            $result['parent_id'] = $parentId;
        }

        return $result;
    }
}